/*************************************************************
* Array.hpp
* 向量、矩阵定义
* 
* copyright colburn (bjay@qq.com)
* created 2022.11.18 
*************************************************************/
#ifndef __COLBURN_ARRAY_HPP__
#define __COLBURN_ARRAY_HPP__
#include <iostream>
#include <string.h>

#define DEBUG 0
#include "../../../inc/DEprintf.h"

using namespace std;

template <class T>
class Array{
	int n =0,m =0;
	T *ele =NULL;
public:
	Array(){}
	Array(int n1, int m1, T* ele1);
	Array(const Array<T> & A);
	
	~Array(){
		if(ele !=NULL){
			DEprintf(1, "elements is at 0x%x\n", ele);
			delete [] ele; //free
			ele =NULL;
		}
	}

	int getRow()  const {return n;}
	int getColumn() const {return m;}
	T* getElement() const {return ele;}
	
	Array operator+(const Array&);
	Array operator+=(const Array&);
	Array operator-(const Array&);
	Array operator-=(const Array&);
	Array operator*(const Array&);
	Array operator*=(const Array&);
	
	Array operator=(const Array&);
	Array Transpose();
	
	template <class U> 
	friend ostream &operator<< (ostream &cout, const Array<U> &p);
	//friend ostream &operator<< (ostream &cout, const Array &p);
};

template <typename T>
Array<T>::Array(int n1, int m1, T* ele1) {
	this->n =n1;
	this->m =m1;
	this->ele =new T[n*m]; //+ - * /
	memcpy (this->ele, ele1, sizeof(T)*n*m);
}

template <class T>
Array<T>::Array(const Array<T> &A) {
	//this->n =A.getRow();
	//this->n =A.n; 
	n =A.n;
	//this->m =A.getColumn();
	m =A.m;
	//this->ele =new T[n*m];
	ele =new T[n*m];

	memcpy (ele, A.ele, sizeof(T)*n*m);
}

template <typename T>
Array<T> Array<T>::operator+(const Array<T>& A) {
	if(n==A.n && m==A.m) {
		T *result =new T[n*m];
		T * pTa =A.ele;

		for(int i =0; i <n; ++i) {
			for(int j =0; j <m; ++j) {
				*(result +i*m +j) = *(ele +i*m +j) +*(pTa +i*m +j);
			}
		}
		return Array(n, m, result);
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator+=(const Array<T>& A) {
	if(n==A.n && m==A.m) {
		T *pTa =A.ele;
		for(int i =0; i <n; ++i) {
			for(int j =0; j <m; ++j) {
				*(ele +i*m +j) += *(pTa +i*m +j);
			}
		}
		return *this;
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator-(const Array<T>& A) {
	if(n==A.n && m==A.m) {
		T *result =new T[n*m];
		T * pTa =A.ele;

		for(int i =0; i <n; ++i) {
			for(int j =0; j <m; ++j) {
				*(result +i*m +j) = *(ele +i*m +j) -*(pTa +i*m +j);
			}
		}
		return Array(n, m, result);
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator-=(const Array<T>& A) {
	if(n==A.n && m==A.m) {
		T * pTa =A.ele;
		for(int i =0; i <n; ++i) {
			for(int j =0; j <m; ++j) {
				*(ele +i*m +j) -= *(pTa +i*m +j);
			}
		}
		return *this;
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator*(const Array<T>& A) {
	if(m==A.n) {
		int Col =A.m;
		T *result =new T[n*Col];
		T * pTa =A.ele;

		for(int i =0; i <n; ++i) {
			for(int j =0; j <Col; ++j) {
				*(result +i*Col +j) =0;
				for(int k =0; k< m; ++k)
					*(result +i*Col +j) += *(ele +i*m +k) * *(pTa +k*m +j);
				//cout <<*(result +i*Col +j) <<endl;
			}
		}
		//for(int i =0; i <n; ++i) {
		//	for(int j =0; j <Col; ++j) {
		//		cout <<*(result +i*Col +j) <<" ";
		//	}
		//	cout <<endl;
		//}
		return Array(n, Col, result);
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator*=(const Array<T>& A) {
	if(m==A.n) {
		int Col =A.m;
		T *result =new T[n*Col];
		T * pTa =A.ele;

		for(int i =0; i <n; ++i) {
			for(int j =0; j <Col; ++j) {
				*(result +i*Col +j) =0;
				for(int k =0; k< m; ++k)
					*(result +i*Col +j) += *(ele +i*m +k) * *(pTa +k*m +j);
			}
		}
		delete [] ele;
		m=Col;
		ele =result;
		return *this;
	}
	return Array(0, 0, NULL);
}

template <typename T>
Array<T> Array<T>::operator=(const Array<T>& A) {
	if(&A !=this){
		if(n *m !=A.n *A.m){
			delete ele;
			ele =new T[A.n *A.m];
		}
		n =A.n;
		m =A.m;
		memcpy(ele, A.ele, sizeof(T) *n *m);
	}
	return *this;
}

template <typename T>
Array<T> Array<T>::Transpose() {

}

template <typename U>
ostream& operator<< (ostream &cout, const Array<U> &p) {
	cout <<"the Array in which the row is "<<p.n <<", the column is " <<p.m <<" elements is at " <<p.ele<<endl;

	for(int i=0; i <p.n; ++i) {
		for(int j=0; j <p.m; ++j) {
			cout <<*(p.ele +i*p.m +j) <<" ";
		}
		cout <<endl;
	}
	return cout;
}
#endif
 
